from Commons import *
import libtcodpy as L
#Area selector class -- handles the selection of areas
#def forbidNone():

class SelectionArray(Rect):#an array that is a selection
	def __init__(self):
		Rect.__init__(self,0,0,0,0)
		self.array = [[]]
	def loadPoints(self,plotpoints):#loads an array of points
		firstpoint = plotpoints.points[0]
		#self.graphics = L.console_new(MAP_WIDTH,MAP_HEIGHT)
		miny = firstpoint.y#initialize the maximums and minimums
		maxy = firstpoint.y
		minx = firstpoint.x
		maxx = firstpoint.x
		for point in plotpoints.points:#keep updating these
			miny = min(miny,point.y)
			maxy = max(maxy,point.y)
			minx = min(minx,point.x)
			maxx = max(maxx,point.x)
		Rect.__init__(self, minx, miny, maxx-minx+1, maxy-miny+1)#make the rectangle
		self.array = [[False
		for y in range(self.height)]
			for x in range(self.width)]
		for point in plotpoints.points:
			self.array[point.x-self.x1][point.y-self.y1] = True
	def __getitem__(self,key):
		return self.array[key]

class Plotpoints:#records points
	def __init__(self):
		self.points = []
	def merge(self, otherplotable):#merge the other points into this
		for point in otherplotable.points:
			self.points.append(point)
	def plot(self, point):#add the point
		self.points.append(point)
	def displaySelection(self, color):#display the selection onto selectiongraphics
		mv = Game()[A_MAP_VIEW]
		for point in self.points:#display each point
			xp = mv.maptoviewX(point.x)
			yp = mv.maptoviewY(point.y)
			if (mv.pointinview(xp,yp)):#if in view
				L.console_set_back(mv.selectiongraphics,xp,yp,color,L.BKGND_SET)
				#L.console_put_char_ex(mv.selectiongraphics,xp,yp,219,color,L.black)
	def __getitem__(self,key):
		return self.points[key]
class Plotarray(SelectionArray):#the array selection, used for selecting something
	def __init__(self):
		SelectionArray.__init__(self)
		self.selection = [[]]
	def displaySelection(self,color,colorWall=L.green):#display everything
		mv = Game()[A_MAP_VIEW]
		for y in range(0,self.height+2,1):
			for x in range(0,self.width+2,1):
				xp = mv.maptoviewX(x+self.x1-1)#x point and y point
				yp = mv.maptoviewY(y+self.y1-1)
				if (mv.pointinview(xp,yp)):#if in view
					if (self.selection[x][y] == 1):#not border
						L.console_put_char_ex(mv.selectiongraphics,xp,yp,' ',L.black,color)#put it at point x1, y1
					if (self.selection[x][y] == 2):#border
						L.console_put_char_ex(mv.selectiongraphics,xp,yp,' ',L.black,colorWall)#put it at point x1, y1
	def implementSelection(self,f,w=None):#implementing two functions for the fill and wall
		for y in range(0,self.height+2,1):
			for x in range(0,self.width+2,1):
				xp = x+self.x1-1#x point and y point
				yp = y+self.y1-1
				if (self.selection[x][y] > 0):#part of the area
					f(self,xp,yp)
					if (self.selection[x][y] == 2 and w != None):
						w(self,xp,yp)
	def selectingAreaFloor(self,x,y):#selecting the floor of the object
		if (x < self.x1-1 or x >= self.x1+self.width+1 or y < self.y1-1 or y >= self.y1+self.height+1):#out of bounds
			return False
		if (self.selection[x-self.x1+1][y-self.y1+1] == 1):#is floor
			return True
		return False
	def selectingArea(self,x,y):#selecting the object
		if (x < self.x1-1 or x >= self.x1+self.width+1 or y < self.y1-1 or y >= self.y1+self.height+1):#out of bounds
			return False
		if (self.selection[x-self.x1+1][y-self.y1+1] > 0):#is area
			return True
		return False
	def startfloodfill(self,conditionfunction,borderdesign=None):#do a floodfill, returning a new selection, condition determines if something can be done
		self.flood = [[False
		for y in range(self.height+2) ] 
			for x in range(self.width+2)]
		self.selection = [[0 for y in range(self.height+2)] for x in range(self.width+2)]#for the final selection
		self.floodfill(0,0)
		#old method, can fill several areas
		for y in range(self.height):
			for x in range(self.width):
				if (not self.flood[x+1][y+1] and conditionfunction(self,x,y)):#Game()[A_MAP][L_TILES][x+self.x1][y+self.y1].isBuildable()):
					self.selection[x+1][y+1] = 1#middle
					if (borderdesign != None):#if borders
						for d in DIRECTIONS:#scan directions for blank tiles
							#either it is the edge of the flood, or the edge of the condition function
							if ((self.flood[x+1+d[0]][y+1+d[1]]) or (not conditionfunction(self,x+d[0],y+d[1]))):
								if (borderdesign):#two different kinds of arrangements
									self.selection[x+1][y+1]=2#wall inside the drawn area
								else:
									self.selection[x+1+d[0]][y+1+d[1]]=2#make the inside space
		#new method planned, fills only one area
		

	def floodfill(self,x,y):
		if (x < 0 or x > self.width+1 or y < 0 or y > self.height+1):#make sure its a valid place
			return
 		if (self.flood[x][y]):#if its flooded
			return
		if ((x > 0 and x<=self.width and y> 0 and y<=self.height) and self.array[x-1][y-1]):#if the array is valid and there is a place
			return
		self.flood[x][y] = True
		self.floodfill(x-1,y)
		self.floodfill(x,y-1)
		self.floodfill(x+1,y)
		self.floodfill(x,y+1)
		
		

class Selection(Plotpoints):
	def __init__(self,initpoint):
		Plotpoints.__init__(self)
		self.points.append(initpoint)
		self.done = False
	def doPoint(self, topoint):
		lastpoint = self.points[len(self.points)-1]
		self.merge(Line(lastpoint,topoint))

class Line(Plotpoints):#a line contains many points, get all the points in a line
	color = L.orange
	def __init__(self,start,end):
		Plotpoints.__init__(self)
		L.line(start.x,start.y,end.x,end.y,self.appendpoint)#use an external library to append the points in order
	def appendpoint(self,x,y):#append a point
		self.points.append(Point(x,y))
		return True
class SelectionPath(Plotpoints):#a path through the maze to select stuff
	color = L.orange
	def __init__(self,start,end, the_map):
		self.start = start
		self.end = end
		self.dx2 = self.start.x-self.end.x
		self.dy2 = self.start.y-self.end.y
		Plotpoints.__init__(self)
		self.map = the_map
		self.line = Line(start,end)
		path = L.path_new_using_function(the_map.xlength, the_map.ylength, self.pathfunction, 0, 1.41)#adding endpoint to user data
		if (not L.path_compute(path,start.x,start.y,end.x,end.y)):
			return
		for i in range(L.path_size(path)):
			x,y = L.path_get(path,i)
			self.points.append(Point(x,y))
	def pathfunction(self, xFrom, yFrom, xTo, yTo, user_data):#ok
		try:
			if (self.map[L_TILES][viewtomapX(xTo)][viewtomapY(yTo)][Game()[A_MAP_VIEW].zview].isBuildable()):
				self.dx1 = xFrom-(self.end.x)
				self.dy1 = yFrom-(self.end.y)
				return 1.0+(abs((self.dx1*self.dy2)-(self.dx2*self.dy1))*0.001)
			return 0.0
		except IndexError:
			return 0.0
